using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using dnAnalytics.Math;
using dnAnalytics.LinearAlgebra;
using dnAnalytics.Exceptions;

namespace dnAnalytics.UnitTests.LinearAlgebra
{
    public abstract class AbstractVectorTest
    {
        protected static readonly double[] testArray = new double[] { -1.1, -2.2, -3.3, 0, 1.1, 2.2 };

        public abstract Vector GetVector(int order);
        public abstract Vector GetVector(int order, double value);
        public abstract Vector GetVector(double[] data);
        public abstract Matrix GetMatrix(int rows, int columns);

        [Test]
        public void AbsoluteMaximum()
        {
            Vector source = GetVector(testArray);
            Vector target = source.Clone();

            double expected = 3.3;
            double actual = target.AbsoluteMaximum();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void AbsoluteMaximumIndex()
        {
            Vector source = GetVector(testArray);
            Vector target = source.Clone();

            int expected = 2;
            int actual = target.AbsoluteMaximumIndex();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void AbsoluteMinimum()
        {
            Vector source = GetVector(testArray);
            Vector target = source.Clone();

            double expected = 0;
            double actual = target.AbsoluteMinimum();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void AbsoluteMinimumIndex()
        {
            Vector source = GetVector(testArray);
            Vector target = source.Clone();

            int expected = 3;
            int actual = target.AbsoluteMinimumIndex();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void AddScalar()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            vector.Add(scalar);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(scalar + testArray[i], vector[i]);
            }
        }

        [Test]
        public void AddScalarResult()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length);
            double scalar = 2.2;
            vector.Add(scalar, result);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(scalar + testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddScalarResultNull()
        {
            Vector vector = GetVector(testArray);
            Vector result = null;
            double scalar = 2.2;
            vector.Add(scalar, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddScalarResultNonConformable()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length + 1);
            double scalar = 2.2;
            vector.Add(scalar, result);
        }

        [Test]
        public void AddVectorInterface()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            vector1.Add(vector2);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(testArray[i] + testArray[i], vector1[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddVectorNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            vector1.Add(vector2);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddVectorNonConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length + 1);
            vector1.Add(vector2);
        }

        [Test]
        public void AddVectorResult()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = GetVector(testArray.Length);
            vector1.Add(vector2, result);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(testArray[i] + testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddVectorResultNull1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Vector result = GetVector(testArray.Length);
            vector1.Add(vector2, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddVectorResultNull2()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = null;
            vector1.Add(vector2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddVectorResultNotConformable1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length + 1);
            Vector result = GetVector(testArray.Length);
            vector1.Add(vector2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddVectorResultNotConformable2()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray);
            Vector result = GetVector(testArray.Length + 1);
            vector1.Add(vector2, result);
        }

        [Test]
        public void Clear()
        {
            Vector vector = GetVector(testArray);
            vector.Clear();
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(0, vector[i]);
            }
        }

        [Test]
        public void Clone()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Assert.AreEqual(vector1.Count, vector2.Count);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(vector1[i], vector2[i]);
            }
        }

        [Test]
        public void CopyTo()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(vector1.Count);
            vector1.CopyTo(vector2);

            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(vector1[i], vector2[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CopyToNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            vector1.CopyTo(vector2);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void CopyToNotConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length + 1);
            vector1.CopyTo(vector2);
        }

        [Test]
        public void Count()
        {
            Vector vector = GetVector(testArray);
            Assert.AreEqual(testArray.Length, vector.Count);
        }

        [Test]
        public void Divide()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            vector.Divide(scalar);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i] / scalar, vector[i]);
            }
        }

        [Test]
        public void DivideResult()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length);
            double scalar = 2.2;
            vector.Divide(scalar, result);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i] / scalar, result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DivideResultNull()
        {
            Vector vector = GetVector(testArray);
            Vector result = null;
            double scalar = 2.2;
            vector.Divide(scalar, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void DivideResultNonConformable()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length + 1);
            double scalar = 2.2;
            vector.Divide(scalar, result);
        }


        [Test]
        public void DotProduct()
        {
            Vector vector = GetVector(6, 2);
            double result = vector.DotProduct();
            Assert.AreEqual(24, result);
        }

        [Test]
        public void DotProductVector()
        {
            Vector vector1 = GetVector(6, 2);
            Vector vector2 = GetVector(6, 2);
            double result = vector1.DotProduct(vector2);
            Assert.AreEqual(24, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DotProductVectorNull()
        {
            Vector vector1 = GetVector(6, 2);
            Vector vector2 = null;
            double result = vector1.DotProduct(vector2);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void DotProductVectorNotConformable()
        {
            Vector vector1 = GetVector(6, 2);
            Vector vector2 = GetVector(vector1.Count + 1, 2);
            double result = vector1.DotProduct(vector2);
        }

        [Test]
        public void GetEnumerator()
        {
            Vector vector = GetVector(testArray);
            foreach (KeyValuePair<int, double> pair in vector) 
            { 
                Assert.AreEqual(testArray[pair.Key], pair.Value); 
            }  
        }

        [Test]
        public void GetEnumeratorRange()
        {
            Range range = new Range(1, 5, 2);
            Vector vector = GetVector(testArray);
            IEnumerator<KeyValuePair<int, double>> iterator = vector.GetEnumerator(range);

            while (iterator.MoveNext())
            {
                KeyValuePair<int, double> pair = iterator.Current;
                // Check that the key (int) is in the range.
                Assert.AreEqual(0, (pair.Key - range.Start) % range.Stride);
                // Check that the value is the correct value
                Assert.AreEqual(testArray[pair.Key], pair.Value);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void GetEnumeratorRangeOutOfRange1()
        {
            Range range = new Range(1, 10, 2);
            Vector vector = GetVector(testArray);
            IEnumerator<KeyValuePair<int, double>> iterator = vector.GetEnumerator(range);
            double value = 0;
            while (iterator.MoveNext())
            {
                value = iterator.Current.Value;
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void GetEnumeratorRangeOutOfRange2()
        {
            Range range = new Range(10, 20, 2);
            Vector vector = GetVector(testArray);
            IEnumerator<KeyValuePair<int, double>> iterator = vector.GetEnumerator(range);
            double value = 0;
            while (iterator.MoveNext())
            {
                value = iterator.Current.Value;
            }
        }


        [Test]
        public void InfinityNorm()
        {
            Vector vector = GetVector(testArray);
            double actual = vector.InfinityNorm();
            double expected = 3.3;
            Assert.AreEqual(expected, actual, 1E15);
        }

        [Test]
        public void L1Norm()
        {
            Vector vector = GetVector(testArray);
            double actual = vector.L1Norm();
            double expected = 9.9;
            Assert.AreEqual(expected, actual, 1E15);
        }

        [Test]
        public void L2Norm()
        {
            Vector vector = GetVector(testArray);
            double actual = vector.L2Norm();
            double expected = 4.975;
            Assert.AreEqual(expected, actual, 1E15);
        }

        [Test]
        public void Maximum()
        {
            Vector vector = GetVector(testArray);

            double expected = 2.2;
            double actual = vector.Maximum();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void MaximumIndex()
        {
            Vector vector = GetVector(testArray);

            int expected = 5;
            int actual = vector.MaximumIndex();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void Minimum()
        {
            Vector vector = GetVector(testArray);

            double expected = -3.3;
            double actual = vector.Minimum();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void MinimumIndex()
        {
            Vector vector = GetVector(testArray);

            int expected = 2;
            int actual = vector.MinimumIndex();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void MultiplyScalar()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            vector.Multiply(scalar);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i] * scalar, vector[i]);
            }
        }

        [Test]
        public void MultiplyScalarResult()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length);
            double scalar = 2.2;
            vector.Multiply(scalar, result);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i] * scalar, result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void MultiplyScalarResultNull()
        {
            Vector vector = GetVector(testArray);
            Vector result = null;
            double scalar = 2.2;
            vector.Multiply(scalar, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyScalarResultNonConformable()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length + 1);
            double scalar = 2.2;
            vector.Multiply(scalar, result);
        }

        [Test]
        public void MultiplyVector()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = vector1.Multiply(vector2);
            for (int i = 0; i < vector1.Count; i++)
            {
                for (int j = 0; j < vector2.Count; j++)
                {
                    Assert.AreEqual(testArray[i] * testArray[j], result[i, j]);
                }
            }
        }

        [Test]
        public void MultiplyVectorResult()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = GetMatrix(vector1.Count, vector2.Count);
            vector1.Multiply(vector2, result);

            for (int i = 0; i < vector1.Count; i++)
            {
                for (int j = 0; j < vector2.Count; j++)
                {
                    Assert.AreEqual(testArray[i] * testArray[j], result[i, j]);
                }
            }
        }



        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void MultiplyVectorNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Matrix result = vector1.Multiply(vector2);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void MultiplyVectorResultMatrixIsNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = null;
            vector1.Multiply(vector2, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void MultiplyVectorResultVectorIsNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Matrix result = GetMatrix(vector1.Count, vector1.Count);
            vector1.Multiply(vector2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyVectorResultMatrixNotConformable1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = GetMatrix(vector1.Count + 1, vector2.Count);
            vector1.Multiply(vector2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyVectorResultMatrixNotConformable2()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = GetMatrix(vector1.Count, vector2.Count + 1);
            vector1.Multiply(vector2, result);
        }


        [Test]
        public void Negate()
        {
            Vector vector = GetVector(testArray);
            vector.Negate();
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(-testArray[i], vector[i]);
            }
        }

        [Test]
        public void NegateResult()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(vector.Count);
            vector.Negate(result);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(-testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void NegateResultNull()
        {
            Vector vector = GetVector(testArray);
            Vector result = null;
            vector.Negate(result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void NegateResultNotConformable()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(vector.Count + 1);
            vector.Negate(result);
        }

        [Test]
        public void SetValues()
        {
            Vector vector = GetVector(testArray.Length);
            vector.SetValues(testArray);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i], vector[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SetValuesNull()
        {
            Vector vector = GetVector(testArray.Length);
            vector.SetValues(null);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SetValuesNotConformable()
        {
            Vector vector = GetVector(testArray.Length + 1);
            vector.SetValues(testArray);
        }

        [Test]
        public void SubtractScalar()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            vector.Subtract(scalar);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i] - scalar, vector[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SubtractScalarResultNull()
        {
            Vector vector = GetVector(testArray);
            Vector result = null;
            double scalar = 2.2;
            vector.Subtract(scalar, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractScalarResultNonConformable()
        {
            Vector vector = GetVector(testArray);
            Vector result = GetVector(testArray.Length - 1);
            double scalar = 2.2;
            vector.Subtract(scalar, result);
        }

        [Test]
        public void SubtractVector()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            vector1.Subtract(vector2);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(testArray[i] - testArray[i], vector1[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SubtractVectorNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            vector1.Subtract(vector2);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractVectorNonConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length - 1);
            vector1.Subtract(vector2);
        }

        [Test]
        public void SubtractVectorResult()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = GetVector(testArray.Length);
            vector1.Subtract(vector2, result);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(testArray[i] - testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SubtractVectorResultNull1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Vector result = GetVector(testArray.Length);
            vector1.Subtract(vector2, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SubtractVectorResultNullInterface2()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = null;
            vector1.Subtract(vector2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractVectorResultNotConformable1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(testArray.Length - 1);
            Vector result = GetVector(testArray.Length);
            vector1.Subtract(vector2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractVectorResultNotConformable2()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = GetVector(testArray.Length - 1);
            vector1.Subtract(vector2, result);
        }

        [Test]
        public void SubVector()
        {
            Vector vector = GetVector(testArray);

            Range range = new Range(0, 5);
            Vector sub = vector.SubVector(range);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(vector[i], sub[i]);
            }

            range = new Range(2, 4, 1);
            sub = vector.SubVector(range);
            for (int i = range.Start, j = 0; i <= range.End; i += range.Stride, j++)
            {
                Assert.AreEqual(vector[i], sub[j]);
            }

            range = new Range(1, 4, 2);
            sub = vector.SubVector(range);
            for (int i = range.Start, j = 0; i <= range.End; i += range.Stride, j++)
            {
                Assert.AreEqual(vector[i], sub[j]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SubVectorArgumentOutOfRange1()
        {
            Vector vector = GetVector(testArray);
            Range range = new Range(6, 10);
            Vector sub = vector.SubVector(range);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SubVectorArgumentOutOfRange2()
        {
            Vector vector = GetVector(testArray);
            Range range = new Range(0, 10);
            Vector sub = vector.SubVector(range);
        }

        [Test]
        public void Sum()
        {
            Vector vector = GetVector(testArray);
            double actual = vector.Sum();
            double expected = 0;
            for (int i = 0; i < testArray.Length; i++)
            {
                expected += testArray[i];
            }
            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void SumMagnitudes()
        {
            Vector vector = GetVector(testArray);
            double actual = vector.SumMagnitudes();
            double expected = 0;
            for (int i = 0; i < testArray.Length; i++)
            {
                expected += System.Math.Abs(testArray[i]);
            }
            Assert.AreEqual(expected, actual, Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        public void Swap()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(vector1.Count);
            vector1.Swap(vector2);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i], vector2[i]);
                Assert.AreEqual(0, vector1[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SwapNull()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            vector1.Swap(vector2);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SwapNotConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(vector1.Count + 1);
            vector1.Swap(vector2);
        }

        [Test]
        public void Item()
        {
            Vector vector = GetVector(testArray.Length);
            for (int i = 0; i < testArray.Length; i++)
            {
                vector[i] = testArray[i];
                Assert.AreEqual(testArray[i], vector[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(IndexOutOfRangeException))]
        public void ItemIndexOutOfRange1()
        {
            Vector vector = GetVector(1);
            vector[-1] = 1;
        }

        [Test]
        [ExpectedException(typeof(IndexOutOfRangeException))]
        public void ItemIndexOutOfRange2()
        {
            Vector vector = GetVector(1);
            vector[2] = 1;
        }

        [Test]
        public void ToArray()
        {
            Vector vector = GetVector(testArray);
            double[] temp = vector.ToArray();
            Assert.AreEqual(vector.Count, temp.Length);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(testArray[i], temp[i]);
            }
        }


        [Test]
        public void OperatorSubtract()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = vector1 - vector2;
            Assert.AreEqual(vector1.Count, result.Count);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(vector1[i] - vector2[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorSubtractNull1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Vector result = vector1 - vector2;
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorSubtractNull2()
        {
            Vector vector1 = null;
            Vector vector2 = GetVector(testArray);
            Vector result = vector1 - vector2;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void OperatorSubtractVectorVectorNonConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(vector1.Count + 1);
            Vector result = vector1 - vector2;
        }

        [Test]
        public void OperatorNegate()
        {
            Vector vector = GetVector(testArray);
            Vector result = -vector;
            Assert.AreEqual(vector.Count, result.Count);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(-vector[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorNegateNull()
        {
            Vector vector = null;
            vector = -vector;
        }

        [Test]
        public void OperatorAdd()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Vector result = vector1 + vector2;
            Assert.AreEqual(vector1.Count, result.Count);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(vector1[i] + vector2[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorAddNull1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Vector result = vector1 + vector2;
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorAddNull2()
        {
            Vector vector1 = null;
            Vector vector2 = GetVector(testArray);
            Vector result = vector1 + vector2;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void OperatorAddNonConformable()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = GetVector(vector1.Count + 1);
            Vector result = vector1 + vector2;
        }

        [Test]
        public void OperatorPlus()
        {
            Vector vector = GetVector(testArray);
            Vector result = +vector;
            Assert.AreEqual(vector.Count, result.Count);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(+vector[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorPlusNull()
        {
            Vector vector = null;
            vector = +vector;
        }

        [Test]
        public void OperatorMultiplyScalarVector()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            Vector result = scalar * vector;
            Assert.AreEqual(vector.Count, result.Count);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(scalar * testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorMultiplyScalarVectorNull()
        {
            Vector vector = null;
            double scalar = 2.2;
            Vector result = scalar * vector;
        }

        [Test]
        public void OperatorMultiplyVectorScalar()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            Vector result = vector * scalar;
            Assert.AreEqual(vector.Count, result.Count);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(vector[i] * scalar, result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorMultiplyVectorNullScalar()
        {
            Vector vector = null;
            double scalar = 2.2;
            Vector result = vector * scalar;
        }

        [Test]
        public void OperatorMultiply()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = vector1.Clone();
            Matrix result = vector1 * vector2;
            Assert.AreEqual(vector1.Count, result.Rows);
            Assert.AreEqual(vector2.Count, result.Columns);
            for (int i = 0; i < vector1.Count; i++)
            {
                for (int j = 0; j < vector2.Count; j++)
                {
                    Assert.AreEqual(vector1[i] * vector2[j], result[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorMultiplyNull1()
        {
            Vector vector1 = GetVector(testArray);
            Vector vector2 = null;
            Matrix result = vector1 * vector2;
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorMultiplyNull2()
        {
            Vector vector1 = null;
            Vector vector2 = GetVector(testArray);
            Matrix result = vector1 * vector2;
        }

        [Test]
        public void OperatorDivide()
        {
            Vector vector = GetVector(testArray);
            double scalar = 2.2;
            Vector result = vector / scalar;
            Assert.AreEqual(vector.Count, result.Count);
            for (int i = 0; i < vector.Count; i++)
            {
                Assert.AreEqual(vector[i] / scalar, result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorDivideNull()
        {
            Vector vector = null;
            double scalar = 2.2;
            Vector result = vector / scalar;
        }

    }
}
